package com.webank.wedatasphere.qualitis.controller.thymeleaf;

import com.alibaba.fastjson.JSONObject;
import com.webank.wedatasphere.qualitis.handler.CommonExecuteTaskService;
import com.webank.wedatasphere.qualitis.handler.CommonJDBCService;
import com.webank.wedatasphere.qualitis.listener.TaskExecuteEvent;
import com.webank.wedatasphere.qualitis.project.dao.repository.ProjectMuLuRepository;
import com.webank.wedatasphere.qualitis.project.dao.repository.ProjectRelationShipRuleRepository;
import com.webank.wedatasphere.qualitis.project.dao.repository.ProjectRepository;
import com.webank.wedatasphere.qualitis.project.entity.Project;
import com.webank.wedatasphere.qualitis.project.entity.ProjectMuLu;
import com.webank.wedatasphere.qualitis.project.entity.ProjectRelationShipRule;
import com.webank.wedatasphere.qualitis.question.constant.OrderStatus;
import com.webank.wedatasphere.qualitis.question.entity.Order;
import com.webank.wedatasphere.qualitis.question.repository.OrderRepository;
import com.webank.wedatasphere.qualitis.response.Grid;
import com.webank.wedatasphere.qualitis.response.Resp;
import com.webank.wedatasphere.qualitis.response.RuleDetailDTO;
import com.webank.wedatasphere.qualitis.rule.dao.repository.RuleDetailInfoVoRepository;
import com.webank.wedatasphere.qualitis.rule.dao.repository.SqlTaskRepository;
import com.webank.wedatasphere.qualitis.rule.entity.RuleDetailInfoVo;
import com.webank.wedatasphere.qualitis.rule.entity.SqlTaskInfo;
import com.webank.wedatasphere.qualitis.util.CommUtils;
import com.webank.wedatasphere.qualitis.util.LocalTimeUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.*;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 调用大数据平台接口，任务信息回调保存
 */
@RestController
@RequestMapping("/sqlTask")
public class SqlTaskInfoController {

    private Logger logger = LoggerFactory.getLogger(SqlTaskInfoController.class);

    /**
     * 任务执行记录
     */
    @Autowired
    private SqlTaskRepository sqlTaskRepository;


    /**
     * 复杂多表查询SQL
     */
    @Autowired
    private CommonJDBCService commonJDBCService;


    /**
     * 菜单目录
     */
    @Autowired
    private ProjectMuLuRepository projectMuLuRepository;

    /**
     * 数据质量标准
     */
    @Autowired
    private ProjectRepository projectRepository;

    /**
     * 需要执行的规则
     */
    @Autowired
    private RuleDetailInfoVoRepository ruleDetailInfoVoRepository;

    /**
     * 标准管理规则中间表
     */
    @Autowired
    private ProjectRelationShipRuleRepository projectRelationShipRuleRepository;


    /**
     * 执行任务服务
     */
    @Autowired
    private CommonExecuteTaskService commonExecuteTaskService;

    /**
     * 工单生成
     */
    @Autowired
    private OrderRepository orderRepository;


    private final ApplicationEventPublisher publisher;

    public SqlTaskInfoController(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }


    // 一分钟之内不刷新
    private final long awaitTime = 1 * 60 * 1000;

    // 最后一次刷新时间
    private volatile long thatLastTime = 0;

    /**
     * 数据源
     *
     * @return
     */
    @RequestMapping(value = {"/list"}, method = RequestMethod.GET)
    public ModelAndView question() {
        return new ModelAndView("layui-admin/task/list");
    }


    @RequestMapping(value = {"/getParentId/datagrid"}, method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public Grid<?> getParentDataGrid(HttpServletRequest request) {
        Sort sort = new Sort(Sort.Direction.ASC, "id");
        //  分页查询
        String page = request.getParameter("page");
        String limit = request.getParameter("rows");
        // 获取条件过滤器
        JSONObject changeBuilder = CommUtils.getJsonObject(request);
        // 组装SQl条件过滤法器
        ExampleMatcher matcher = CommUtils.getSqlWhere(request);
        // 序列化对象
        Project itemQueryWhere = changeBuilder.toJavaObject(Project.class);
        itemQueryWhere.setFbzt("已发布");
        // 分页插件
        Pageable pageable = PageRequest.of(Integer.parseInt(page) - 1, Integer.parseInt(limit), sort);
        // 条件过滤器插件
        Example<Project> example = Example.of(itemQueryWhere, matcher);
        // 条件过滤+分页
        Page<Project> all = projectRepository.findAll(example, pageable);
        List<ProjectMuLu> muLuRepositoryAll = projectMuLuRepository.findAll();
        List<Project> content = all.getContent();
        if (CollectionUtils.isNotEmpty(content)) {
            for (Project project : content) {
                String sjzlbzml = project.getSjzlbzml();
                for (ProjectMuLu muLu : muLuRepositoryAll) {
                    if (String.valueOf(muLu.getId()).equals(sjzlbzml)) {
                        project.setSjzlbzml(muLu.getTitle());
                    }
                }
            }
        }
        long totalElements = all.getTotalElements();
        return Grid.OkPage(CollectionUtils.isEmpty(content) ? new ArrayList<>() : content, totalElements);
    }

    /**
     * 懒加载--根据父级ID查询子级数据
     *
     * @param request
     * @return
     */
    @RequestMapping(value = {"/byParentId/datagrid"}, method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public Grid<?> getSonDataGridByParentId(HttpServletRequest request) {
        //  分页查询
        String parentId = request.getParameter("parentId");
        if (StringUtils.isBlank(parentId)) {
            logger.error("parentId is null|数据标准的Id不能为空");
            return Grid.OkPage(new ArrayList<>(), 0);
        }
        return commonJDBCService.queryTaskManyTableInSqlWhere(Long.parseLong(parentId), 1, 5);
    }

    /**
     * 刷新执行任务状态
     *
     * @param request request
     * @return Resp
     */
    @RequestMapping(value = {"/refresh"}, method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public Resp<?> refresh(HttpServletRequest request) {
        //  分页查询
        if ((System.currentTimeMillis() - thatLastTime) < awaitTime) {
            // 刷新执行状态
            return Resp.error("耐心等待任务执行完毕");
        }
        thatLastTime = System.currentTimeMillis();
        return Resp.Ok("刷新成功");
    }

    /**
     * 创建问题工单
     *
     * @param request request
     * @return Resp
     */
    @RequestMapping(value = {"/createQuestForm"}, method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    @Transactional
    public Resp<?> createQuestForm(HttpServletRequest request) {
        String projectId = request.getParameter("projectId");
        int maxSortByProjectId = sqlTaskRepository.getMaxSortByProjectId(projectId);
        List<SqlTaskInfo> sqlTaskInfos = sqlTaskRepository.findByProjectIdAndSort(projectId, maxSortByProjectId);
        if (CollectionUtils.isNotEmpty(sqlTaskInfos)){
            for (SqlTaskInfo taskInfo : sqlTaskInfos) {
                if (taskInfo.getCheckStatus().equals("校验通过")){
                    continue;
                }
                Order order = new Order();
                order.setCreateTime(new Date());
                order.setName(taskInfo.getProjectName()+ ":" + taskInfo.getTaskName());
                order.setQualityStandard(Long.valueOf(projectId));
                order.setQualityStandardName(taskInfo.getProjectName());
                order.setTaskId(taskInfo.getId());
                order.setVersion(String.valueOf(maxSortByProjectId));
                order.setStatus(OrderStatus.NOT_RESOLVE.getCode());
                orderRepository.save(order);
            }
        }
        return Resp.Ok("创建成功");
    }

    /**
     * 获取版本次数
     *
     * @param request request
     * @return Resp
     */
    @RequestMapping(value = {"/getSort"}, method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public Resp<?> getSort(HttpServletRequest request) {

        List<SqlTaskInfo> sqlTaskInfos = sqlTaskRepository.findByProjectId(request.getParameter("projectId"));
        if (CollectionUtils.isEmpty(sqlTaskInfos)){
            return Resp.error("没有执行任务");
        }
        List<Integer> sortIds = sqlTaskInfos.stream().map(SqlTaskInfo::getSort).distinct().collect(Collectors.toList());
        return Resp.Ok(sortIds);
    }
    /**
     * 运行标准里面的规则
     *
     * @return
     */
    @RequestMapping(value = {"/runTask"}, method = RequestMethod.POST)
    @ResponseBody
    public Resp<?> runTask(HttpServletRequest request) {
        String parentId = request.getParameter("parentId");
        if (StringUtils.isBlank(parentId)) {
            logger.error("parentId is null|数据标准的Id不能为空");
            return Resp.error("parentId is null|数据标准的Id不能为空");
        }
        Long projectId = Long.parseLong(parentId);
        // 获取标准ID---根据标准ID查询规则
        List<ProjectRelationShipRule> shipRules = projectRelationShipRuleRepository.findByProjectId(projectId);
        if (CollectionUtils.isNotEmpty(shipRules)) {
            // 获取关联的规则ID
            List<Long> ruleIds = shipRules.stream().map(ProjectRelationShipRule::getRuleId).collect(Collectors.toList());
            // 根据规则ID找到对应的规则
            List<RuleDetailInfoVo> thatObj = ruleDetailInfoVoRepository.findAllById(ruleIds);
            if (CollectionUtils.isNotEmpty(thatObj)) {
                Resp<Object> resp = null;
                try {
                    resp = executeTask(thatObj, projectId, shipRules.get(0).getProjectName());
                } catch (Exception e) {
                    logger.error("执行规则失败", e);
                    resp = Resp.error("执行规则失败");

                }
                return resp;
            }
        }
        return Resp.error("该标准里里面未找到执行规则");
    }


    /**
     * 调用线程池异步执行任务
     *
     * @param thatObj     thatObj
     * @param projectId   projectId
     * @param projectName projectName
     * @return
     */
    public Resp<Object> executeTask(List<RuleDetailInfoVo> thatObj, Long projectId, String projectName) throws InterruptedException {
        ResponseEntity<JSONObject> entity = commonExecuteTaskService.login();
        if (entity != null && entity.getStatusCode().value() == HttpStatus.SC_OK) {
            int status = entity.getBody().getInteger("status");
            if (status != 0) {
                return Resp.error("执行规则失败：调用底层计算引擎失败");
            }
        }
        String beginTime = LocalTimeUtils.getCurrentTime();
        List<SqlTaskInfo> oldTasks = sqlTaskRepository.findByProjectId(String.valueOf(projectId));
        int thatVersion = 1;
        if (CollectionUtils.isNotEmpty(oldTasks)) {
            thatVersion = oldTasks.stream().min((o1, o2) -> o2.getSort().compareTo(o1.getSort())).get().getSort()
                    + 1;
        }
        final int sortValue = thatVersion;
        // 异步发起事件
        publisher.publishEvent(new TaskExecuteEvent(this, projectId, thatObj, projectName, beginTime, sortValue));
        return Resp.Ok("初始化任务" + thatObj.size() + "条,成功");
    }


    /**
     * 详情
     *
     * @return
     */
    @RequestMapping(value = {"/detail"}, method = RequestMethod.GET)
    public ModelAndView detail(HttpServletRequest request) {
        ModelAndView view = new ModelAndView("layui-admin/datasource/detail");
        String id = request.getParameter("id");
        if (StringUtils.isNotBlank(id)) {
            projectRepository.findById(Long.valueOf(id)).ifPresent(view::addObject);
        } else {
            view.addObject(new Project());
        }
        return view;
    }


    /**
     * 详情
     *
     * @return
     */
    @RequestMapping(value = {"/taskInfoView"}, method = RequestMethod.GET)
    public ModelAndView getByProjectIdAndSort(HttpServletRequest request) {
        ModelAndView view = new ModelAndView("layui-admin/task/detail");
        String projectId = request.getParameter("projectId");
        String sort = request.getParameter("sort");
        List<RuleDetailDTO> ruleDetailDTOS = new ArrayList<>();
        if (StringUtils.isNotBlank(projectId) && StringUtils.isNotBlank(sort)) {
            // 展示数据质量标准的信息
            projectRepository.findById(Long.valueOf(projectId)).ifPresent(project -> {
                view.addObject("project", project);
            });
            // 展示数据质量标准任务执行情况的信息
            List<SqlTaskInfo> sqlTaskInfos = sqlTaskRepository.findByProjectIdAndSort(projectId, Integer.parseInt(sort));
            long ruleSuccess = sqlTaskInfos.stream().filter(sqlTaskInfo -> sqlTaskInfo.getCheckStatus().equals("校验通过")).count();
            String endTime = sqlTaskInfos.stream().max(Comparator.comparing(SqlTaskInfo::getId)).get().getEndTime();
            view.addObject("ruleSuccess", ruleSuccess);
            view.addObject("ruleFail", sqlTaskInfos.size() - ruleSuccess);
            view.addObject("ruleTotal", sqlTaskInfos.size());
            view.addObject("beginTime",sqlTaskInfos.get(0).getBeginTime());
            view.addObject("endTime", endTime);
            // 查询规则相关的信息
            for (SqlTaskInfo taskInfo : sqlTaskInfos) {
                // 获取规则信息
                RuleDetailInfoVo ruleDetailInfoVo = ruleDetailInfoVoRepository.findById(taskInfo.getRuleNewId()).get();
                RuleDetailDTO ruleDetailDTO = new RuleDetailDTO();
                ruleDetailDTO.setRuleName(ruleDetailInfoVo.getRuleName());
                ruleDetailDTO.setRuleTemplate(ruleDetailInfoVo.getRuleTemplate());
                ruleDetailDTO.setRuleType(ruleDetailInfoVo.getRuleType());
                ruleDetailDTO.setCheckStatus(taskInfo.getCheckStatus());
                ruleDetailDTO.setDatabaseName(ruleDetailInfoVo.getDatabaseName());
                ruleDetailDTO.setFieldName(ruleDetailInfoVo.getFieldName());
                ruleDetailDTO.setTableName(ruleDetailInfoVo.getTableName());
                ruleDetailDTO.setDataSourceEngine(ruleDetailInfoVo.getDataSourceEngine());
                String desc = "期望执行结果是：" + ruleDetailInfoVo.getCompareType() +" "+ ruleDetailInfoVo.getCheckThreshold();
                ruleDetailDTO.setDesc(desc);
                ruleDetailDTOS.add(ruleDetailDTO);
            }
            view.addObject("ruleDetailDTOS", ruleDetailDTOS);
        } else {
            view.addObject("project",new Project());
            view.addObject("ruleDetailDTOS", ruleDetailDTOS);
            view.addObject("ruleSuccess", "---");
            view.addObject("ruleFail", "---");
            view.addObject("ruleTotal", "---");
            view.addObject("beginTime","---");
            view.addObject("endTime", "---");
        }
        return view;
    }

}
